package com.thysdy.flowable.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.thysdy.flowable.entity.*;
import com.thysdy.flowable.enums.CodeEnum;
import com.thysdy.flowable.exception.MyException;
import com.thysdy.flowable.flowable.BaseProcessService;
import com.thysdy.flowable.flowable.DeleteFlowableProcessInstanceCmd;
import com.thysdy.flowable.mapper.ProcessInstanceMapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Transactional(rollbackFor = Exception.class)
@Service
@Slf4j
public class InstanceService extends BaseProcessService {
    @Resource
    ProcessInstanceMapper processInstanceMapper;
    @Resource
    RestTemplate restTemplate;
    @Resource
    IBusinessStaconfigService businessStaconfigService;
    /**
     * 激活流程实例
     */
    private final int jh = 1;
    /**
     * 挂起流程实例
     */
    private final int gq = 2;
    private final int dataSize = 2;

    public int suspendOrActivateProcessInstanceById(List<String> processInstanceIds, int suspensionState) throws MyException {
        try {
            if (suspensionState == gq) {
                for (String processInstanceId : processInstanceIds) {
                    runtimeService.suspendProcessInstanceById(processInstanceId);
                }
            } else if (suspensionState == jh) {
                for (String processInstanceId : processInstanceIds) {
                    runtimeService.activateProcessInstanceById(processInstanceId);
                }

            }
        } catch (Exception e) {
            throw new MyException(CodeEnum.commonException);
        }
        return suspensionState;
    }

    public void deleteInstanceCompletely(List<String> processInstanceIds) throws Exception {
        try {
            for (String processInstanceId : processInstanceIds) {
                long count = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).count();
                if (count > 0) {
                    DeleteFlowableProcessInstanceCmd cmd = new DeleteFlowableProcessInstanceCmd(processInstanceId, "删除流程实例", true);
                    managementService.executeCommand(cmd);
                } else {
                    historyService.deleteHistoricProcessInstance(processInstanceId);
                }
            }
        } catch (Exception e) {
            throw e;
        }
    }

    public PageEntity getFlowableInstances(ProcessInstanceQueryVo queryVo) throws MyException {
        PageEntity pageEntity = null;
        List<ProcessInstanceVo> instances = new ArrayList<>();
        try {
            List<String> dates = null;
            dates = queryVo.getDate();
            if (null != dates && dates.size() == dataSize) {
                queryVo.setBeginTime(dates.get(0));
                queryVo.setEndTime(dates.get(1));
            }
            Page<ProcessInstanceVo> page = new Page<>(queryVo.getNowPage(), queryVo.getPageSize());
            IPage<ProcessInstanceVo> instancePage = processInstanceMapper.getFlowableInstances(page, queryVo);
            instances = instancePage.getRecords();

            for (ProcessInstanceVo instanceVo : instances) {
                List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery().processInstanceId(instanceVo.getProcessInstanceId()).list();
                Map<String, Object> variables = new HashMap<>();
                for (int i = 0; i < list.size(); i++) {
                    HistoricVariableInstance historicVariableInstance = list.get(i);
                    String name = historicVariableInstance.getVariableName();
                    Object object = historicVariableInstance.getValue();
                    variables.put(name, object);
                }
//                if (null != instanceVo.getEndTime()) {
//                    variables.put("state", "结束");
//                }
                instanceVo.setVariables(variables);
            }
            pageEntity = new PageEntity(instancePage.getTotal(), instancePage.getPages(), instancePage.getSize(), instancePage.getCurrent(), instances);

        } catch (Exception e) {
            e.printStackTrace();
            throw new MyException(CodeEnum.commonException);
        }
        return pageEntity;
    }

    public void revokeProcessInstance(RequestVo requestVo) throws MyException {
        try {
            if (StringUtils.isNotBlank(requestVo.getInstanceId())) {
                String instanceId = requestVo.getInstanceId();
                ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
                if (null != instance) {
                    //删除流程实例
                    List<String> ids = new ArrayList<>();
                    ids.add(instanceId);
                    deleteInstanceCompletely(ids);
                    //更新业务单据状态
                    String definitionKey = instance.getProcessDefinitionKey();
                    //根据流程定义key查询url和状态参数
                    LambdaQueryWrapper<BusinessStaconfig> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(BusinessStaconfig::getBusinesskey, definitionKey);
                    BusinessStaconfig staconfig = businessStaconfigService.getOne(queryWrapper);
                    if (null != staconfig) {
                        //封装请求参数
                        ServiceRequestVo sReq = new ServiceRequestVo();
                        sReq.setProcessInstanceId(instanceId);
                        sReq.setProcessDefinitionKey(instance.getProcessDefinitionKey());
                        sReq.setBusinessKey(instance.getBusinessKey());
                        sReq.setUrl(staconfig.getUrl());
                        Map<String, Object> params = new HashMap<>();
                        params.put("validsta", staconfig.getState());
                        sReq.setParams(params);
                        log.info("撤回传参-----》"+sReq);
                        //调用更新状态接口
                        updateBusinessState(sReq);
                    }

                } else {
                    throw new MyException(409, "撤回失败：查询正在执行流程实例失败!");
                }
            } else {
                throw new MyException(CodeEnum.paramError);
            }
        } catch (MyException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("revokeProcessInstance error!", e);
            throw new MyException(CodeEnum.commonException);
        }

    }

    private void updateBusinessState(ServiceRequestVo serviceRequestVo) throws MyException {
        try {
            ResponseEntity<String> stringResponseEntity = restTemplate.postForEntity(serviceRequestVo.getUrl(), serviceRequestVo, String.class);
            log.info("updateBusinessState result" + stringResponseEntity);
        } catch (Exception e) {
            throw new MyException(410, "撤回失败：更新业务状态失败!");
        }
    }

    public List<ProcessInstanceVo> getFlowableInstancesByBusinessAndDefinitionKey(RequestVo requestVo) throws MyException {

        List<ProcessInstanceVo> instances = null;
        try {
            if (StringUtils.isNotBlank(requestVo.getBusinessKey()) && StringUtils.isNotBlank(requestVo.getProcessDefinitionKey())) {
                instances = processInstanceMapper.getFlowableInstancesByBusinessAndDefinitionKey(requestVo);
                for (ProcessInstanceVo instanceVo : instances) {
                    List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery().processInstanceId(instanceVo.getProcessInstanceId()).list();
                    Map<String, Object> variables = new HashMap<>();
                    for (int i = 0; i < list.size(); i++) {
                        HistoricVariableInstance historicVariableInstance = list.get(i);
                        String name = historicVariableInstance.getVariableName();
                        Object object = historicVariableInstance.getValue();
                        variables.put(name, object);
                    }
                    instanceVo.setVariables(variables);
                }
            } else {
                throw new MyException(CodeEnum.paramError);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("===>getFlowableInstancesByBusinessAndDefinitionKey error!", e);
            throw new MyException(CodeEnum.commonException);
        }
        return instances;

    }

    public ProcessInstanceVo getNewestFlowableInstancesByBusinessAndDefinitionKey(RequestVo requestVo) throws MyException {
        ProcessInstanceVo processInstanceVo = null;
        List<ProcessInstanceVo> instances = null;
        try {
            if (StringUtils.isNotBlank(requestVo.getBusinessKey()) && StringUtils.isNotBlank(requestVo.getProcessDefinitionKey())) {
                instances = processInstanceMapper.getFlowableInstancesByBusinessAndDefinitionKey(requestVo);
                if (null != instances && !instances.isEmpty()) {
                    processInstanceVo = instances.get(0);
                    List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceVo.getProcessInstanceId()).list();
                    Map<String, Object> variables = new HashMap<>();
                    for (int i = 0; i < list.size(); i++) {
                        HistoricVariableInstance historicVariableInstance = list.get(i);
                        String name = historicVariableInstance.getVariableName();
                        Object object = historicVariableInstance.getValue();
                        variables.put(name, object);
                    }
                    processInstanceVo.setVariables(variables);
                }
                return processInstanceVo;
            } else {
                throw new MyException(CodeEnum.paramError);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("===>getNewestFlowableInstancesByBusinessAndDefinitionKey error!", e);
            throw new MyException(CodeEnum.commonException);
        }

    }
}
